﻿#region [ License information          ]
/* ************************************************************
 *
 * Copyright (c) Bjørn Bouet Smith, 2012
 *
 * This source code is subject to terms and conditions of 
 * Microsoft Public License (Ms-PL).
 * 
 * A copy of the license can be found in the license.txt
 * file at the root of this distribution. If you can not 
 * locate the License, please send an email to bjornsmith@gmail.com
 * 
 * By using this source code in any fashion, you are 
 * agreeing to be bound by the terms of the Microsoft 
 * Public License.
 *
 * You must not remove this notice, or any other, from this
 * software.
 *
 * ************************************************************/
#endregion

using System;
using System.Linq;
using Smith.BuildExtensions.Logging;

namespace Smith.BuildExtensions.ConfigurationTransformation
{
    /// <summary>
    /// Class that selects the correct value to use for a given configuration key
    /// </summary>
    public class ValueSelector : IValueSelector
    {
        private readonly ILogWriter logger;
        private readonly IConfigReader configReader;
        private ConfigSettings baseSettings;
        private ConfigSettings buildSettings;
        private ConfigSettings projectSettings;

        /// <summary>
        /// Initializes a new instance of the <see cref="ValueSelector"/> class.
        /// </summary>
        /// <param name="logger">The logger.</param>
        /// <param name="configReader">The config reader.</param>
        public ValueSelector(
            ILogWriter logger,
            IConfigReader configReader)
        {
            this.logger = logger;
            this.configReader = configReader;
            ReadConfigurations();
        }

        private void ReadConfigurations()
        {
            // Read out the base configuration
            baseSettings = configReader.GetBaseConfig();


            // Read out the build target specific configuration
            if (!configReader.TryGetBuildConfigurationConfig(out buildSettings))
            {
                logger.LogMessage(new Message(MessageLevel.Warn, "Settings file for configuration:{0} was not found", configReader.BuildConfiguration));
            }

            // Try to read out the project specific configuration
            configReader.TryGetProjectConfigurationConfig(out projectSettings);
        }

        /// <summary>
        /// Selects the correct value based on the values in the configsettings
        /// </summary>
        /// <param name="key">The configuration key to get the value for.</param>
        /// <returns>The value for the key.</returns>
        public string SelectValue(string key)
        {
            Func<ConfigSetting, bool> predicate = s => s.Key == key;

            ConfigSetting requested = baseSettings.Settings.FirstOrDefault(predicate);
            ConfigSetting configSetting = buildSettings.Settings.FirstOrDefault(predicate);
            ConfigSetting projectSetting = projectSettings.Settings.FirstOrDefault(predicate);
            if (requested != null)
            {
                string value = requested.Value;
                if (requested.Overwritable && configSetting != null)
                {
                    value = configSetting.Value;
                }
                if (requested.Overwritable && projectSetting != null)
                {
                    value = projectSetting.Value;
                }

                return value;
            }
            
            if (configSetting == null && projectSetting == null)
            {
                logger.LogMessage(new Message(MessageLevel.Error, "Setting for key:{0} not found in either base, configuration or project settings", key));
                return null;
            }
                
            return projectSetting != null ? projectSetting.Value : configSetting.Value;
        }
    }
}
